package com.robotic.route.service.impl;

import java.text.ParseException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.robotic.common.utils.DateUtils;
import com.robotic.common.utils.ExceptionUtil;
import com.robotic.common.utils.StringUtils;
import com.robotic.kafka.KafkaProducerService;
import com.robotic.minio.MinioService;
import com.robotic.minio.RTSPFrameCaptureWithJavaCV;
import com.robotic.quartz.domain.SysJob;
import com.robotic.quartz.mapper.SysJobMapper;
import com.robotic.route.domain.InspectionRecord;
import com.robotic.route.domain.InspectionRecordDetails;
import com.robotic.route.mapper.InspectionRecordDetailsMapper;
import com.robotic.route.mapper.InspectionRecordMapper;
import com.robotic.route.service.IInspectionRecordService;
import com.robotic.sensor.config.DynamicRuleValidator;
import com.robotic.sensor.config.ModbusTcpGasServer;
import com.robotic.sensor.config.ModbusTcpHeatServer;
import com.robotic.sensor.config.ModbusTcpIoServer;
import com.robotic.system.service.ISysDictDataService;
import com.robotic.system.service.ISysDictTypeService;
import com.robotic.tcp.NavigationControl;
import com.robotic.tcp.NavigationParameters;
import com.robotic.tcp.RobotNavigator;
import com.robotic.udp.ExecuteNavigation;
import com.robotic.udp.UnifiedUDPReceiver;
import com.robotic.sensor.service.ISensorDataService;
import com.robotic.sensor.service.IRegionStandardService;
import com.robotic.sensor.service.SensorDataJudgementService;
import com.robotic.sensor.service.CoordinateRegionService;
import com.robotic.sensor.service.RobotCoordinateMonitorService;
import com.robotic.sensor.domain.SensorData;
import com.robotic.sensor.domain.RegionStandard;
import com.robotic.tcp.RobotMonitor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.quartz.CronExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import com.robotic.route.mapper.RoutePointDetailMapper;
import com.robotic.route.domain.RoutePointDetail;
import com.robotic.route.service.IRoutePointDetailService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import static com.robotic.tcp.RobotMonitor.robotX;
import static com.robotic.tcp.RobotMonitor.robotY;

/**
 * 路线点位维护Service业务层处理
 *
 * @author tian
 * @date 2025-08-21
 */
@Slf4j
@Service("routePointDetailServiceImpl")
public class RoutePointDetailServiceImpl extends ServiceImpl<RoutePointDetailMapper, RoutePointDetail> implements IRoutePointDetailService {
    @Autowired
    private RoutePointDetailMapper routePointDetailMapper;

    @Autowired
    private ExecuteNavigation executeNavigation;

    @Autowired
    private RTSPFrameCaptureWithJavaCV rtspFrameCaptureWithJavaCV;

    @Autowired
    private MinioService minioService;

    @Autowired
    private KafkaProducerService kafkaProducerService;

    @Autowired
    private RobotNavigator navigator;

    @Autowired
    private NavigationControl navigationControl;

    @Autowired
    private ISensorDataService sensorDataService;

    @Autowired
    private IRegionStandardService regionStandardService;

    @Autowired
    private SensorDataJudgementService sensorDataJudgementService;

    @Autowired
    private CoordinateRegionService coordinateRegionService;

    @Autowired
    private RobotCoordinateMonitorService robotCoordinateMonitorService;

    @Autowired
    private InspectionRecordDetailsMapper recordDetailsMapper;

    @Autowired
    private IInspectionRecordService recordService;

    @Autowired
    private InspectionRecordMapper recordMapper;

    @Autowired
    private DynamicRuleValidator dynamicRuleValidator;

    @Autowired
    private ModbusTcpGasServer modbusTcpGasServer;

    @Autowired
    private ModbusTcpHeatServer modbusTcpHeatServer;

    @Autowired
    private SysJobMapper sysJobMapper;

    @Autowired
    private ModbusTcpIoServer modbusTcpIoServer;

    @Autowired
    private ISysDictDataService sysDictDataService;

    private Long taskStartTime = null;

    private static final ExecutorService executorService = Executors.newSingleThreadExecutor();

    private String pointCode = null;

    private String routeCode = null;

    private boolean isBreak = false;

    // 定义一个距离阈值（单位：米）。如果机器人与起点的距离大于这个值，则任务失败。
    // 这个值可以根据实际应用场景调整，也可以放到配置文件中。
    private static final double DISTANCE_THRESHOLD = 5; // 例如，0.5米

    public static boolean startPlayer = false;

    public static String executingTask = null;

    public static boolean isCancelNavigation = false;

    /**
     * 查询路线点位维护
     *
     * @param id 路线点位维护主键
     * @return 路线点位维护
     */
    @Override
    public RoutePointDetail selectRoutePointDetailById(Long id) {
        return routePointDetailMapper.selectById(id);
    }

    /**
     * 查询路线点位维护列表
     *
     * @param routePointDetail 路线点位维护
     * @return 路线点位维护
     */
    @Override
    public List<RoutePointDetail> selectRoutePointDetailList(RoutePointDetail routePointDetail) {
        LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
        queryWrapper.eq(StringUtils.isNotEmpty(routePointDetail.getRouteCode()),
                RoutePointDetail::getRouteCode, routePointDetail.getRouteCode());
        queryWrapper.like(StringUtils.isNotEmpty(routePointDetail.getPointName()),
                RoutePointDetail::getPointName, routePointDetail.getPointName());
        queryWrapper.like(StringUtils.isNotEmpty(routePointDetail.getRegion()),
                RoutePointDetail::getRegion, routePointDetail.getRegion());
        queryWrapper.ne(RoutePointDetail::getPointInfo, "0"); // 这个 NE 条件现在会一直生效
        queryWrapper.and(
                StringUtils.isNotEmpty(routePointDetail.getRouteName()),
                i -> i.like(RoutePointDetail::getRouteName, routePointDetail.getRouteName())
                        .or()
                        .like(RoutePointDetail::getRouteCode, routePointDetail.getRouteName())
        );
        return routePointDetailMapper.selectList(queryWrapper);
    }

    /**
     * 新增路线点位维护
     *
     * @param routePointDetail 路线点位维护
     * @return 结果
     */
    @Override
    public int insertRoutePointDetail(RoutePointDetail routePointDetail) {
        routePointDetail.setCreateTime(DateUtils.getNowDate());
        return routePointDetailMapper.insertRoutePointDetail(routePointDetail);
    }

    /**
     * 修改路线点位维护
     *
     * @param routePointDetail 路线点位维护
     * @return 结果
     */
    @Override
    public boolean updateRoutePointDetail(RoutePointDetail routePointDetail) {
        String routeName = routePointDetail.getRouteName();
        String routeCode = routePointDetail.getRouteCode();
        routePointDetail.setUpdateTime(DateUtils.getNowDate());
        if (StringUtils.isNotEmpty(routeName) && StringUtils.isNotEmpty(routeCode)) {
            LambdaUpdateWrapper<RoutePointDetail> wrapper = Wrappers.lambdaUpdate(RoutePointDetail.class);
            wrapper.set(StringUtils.isNotEmpty(routeName), RoutePointDetail::getRouteName, routeName);
            wrapper.eq(RoutePointDetail::getRouteCode, routeCode);
            this.update(wrapper);
        }

        LambdaUpdateWrapper<RoutePointDetail> updateWrapper = Wrappers.lambdaUpdate(RoutePointDetail.class);
        updateWrapper.set(StringUtils.isNotEmpty(routePointDetail.getPointName()), RoutePointDetail::getPointName, routePointDetail.getPointName());
        updateWrapper.set(StringUtils.isNotEmpty(routePointDetail.getRegion()), RoutePointDetail::getRegion, routePointDetail.getRegion());
        updateWrapper.set(StringUtils.isNotEmpty(routePointDetail.getCheckType()), RoutePointDetail::getCheckType, routePointDetail.getCheckType());
        updateWrapper.set(StringUtils.isNotEmpty(routePointDetail.getRemark()), RoutePointDetail::getRemark, routePointDetail.getRemark());
        updateWrapper.set(StringUtils.isNotEmpty(routePointDetail.getDeviceType()), RoutePointDetail::getDeviceType, routePointDetail.getDeviceType());
        updateWrapper.set(StringUtils.isNotEmpty(routePointDetail.getTemperatureCheck()), RoutePointDetail::getTemperatureCheck, routePointDetail.getTemperatureCheck());
        updateWrapper.set(StringUtils.isNotEmpty(routePointDetail.getGasCheck()), RoutePointDetail::getGasCheck, routePointDetail.getGasCheck());
        updateWrapper.set(StringUtils.isNotEmpty(routePointDetail.getModel()), RoutePointDetail::getModel, routePointDetail.getModel());
        updateWrapper.set(RoutePointDetail::getUpdateTime, DateUtils.getNowDate());
        updateWrapper.eq(RoutePointDetail::getId, routePointDetail.getId());

        return this.update(updateWrapper);
    }

    /**
     * 批量删除路线点位维护
     *
     * @param ids 需要删除的路线点位维护主键
     * @return 结果
     */
    @Override
    public int deleteRoutePointDetailByIds(Long[] ids) {
        return routePointDetailMapper.deleteRoutePointDetailByIds(ids);
    }

    /**
     * 删除路线点位维护信息
     *
     * @param id 路线点位维护主键
     * @return 结果
     */
    @Override
    public int deleteRoutePointDetailById(Long id) {
        return routePointDetailMapper.deleteRoutePointDetailById(id);
    }

    @Override
    @Transactional
    public int synchroRoute() {
        try {
            // 从导航文件中获取最新的路由点位内容
            Map<String, String> fileContents = executeNavigation.getFileContents();
            if (fileContents.isEmpty()) {
                return 0; // 没有内容需要处理，正常返回
            }
            // 1. 筛选出需要更新的路由：从文件中的所有路由（keyList），找出在数据库中 RouteName 为空的那些。
            List<String> keyList = new ArrayList<>(fileContents.keySet());

            // 仅当 keyList 不为空时才继续，以避免不必要的数据库查询
            LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);

            // 1. 从数据库中查询出 keyList 中存在的所有路由编码
            queryWrapper.in(RoutePointDetail::getRouteCode, keyList);
            queryWrapper.select(RoutePointDetail::getRouteCode); // 只查询 routeCode 字段以提高效率

            List<RoutePointDetail> existingDetails = baseMapper.selectList(queryWrapper);

            // 2. 从返回的对象列表中提取出路由编码字符串，并放入一个Set中以便高效查询
            Set<String> existingRouteCodes = existingDetails.stream()
                    .map(RoutePointDetail::getRouteCode)
                    .collect(Collectors.toSet());

            // 3. 通过计算差集找出不存在的路由编码
            List<String> nonExistentRouteCodes = keyList.stream()
                    .filter(key -> !existingRouteCodes.contains(key))
                    .collect(Collectors.toList());


            LambdaQueryWrapper<RoutePointDetail> query = Wrappers.lambdaQuery(RoutePointDetail.class);
            query.in(RoutePointDetail::getRouteCode, keyList);
            query.select(RoutePointDetail::getRouteCode); // 只查询出路由编码，并去重
            query.isNull(RoutePointDetail::getRouteName); // 核心逻辑：查询 RouteName 为空的记录

            // 从数据库查询，得到一个需要被更新的 RouteCode 集合
            List<RoutePointDetail> detailsToUpdate = baseMapper.selectList(query);

            Set<String> updatableRouteCodes = detailsToUpdate.stream()
                    .map(RoutePointDetail::getRouteCode)
                    .collect(Collectors.toSet());

            updatableRouteCodes.addAll(nonExistentRouteCodes);
            // 如果没有需要更新的路由（即所有路由都有名字），则直接返回
            if (updatableRouteCodes.isEmpty()) {
                return 0;
            }

            // 2. 删除这些路由的所有旧的点位数据，为插入新数据做准备
            LambdaQueryWrapper<RoutePointDetail> deleteWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
            deleteWrapper.in(RoutePointDetail::getRouteCode, updatableRouteCodes);
            baseMapper.delete(deleteWrapper);

            // 3. 准备要批量插入的新点位数据
            List<RoutePointDetail> newDetailsToInsert = new ArrayList<>();
            for (Map.Entry<String, String> entry : fileContents.entrySet()) {
                String routeCode = entry.getKey();
                // 只处理那些被筛选出来的、需要更新的路由
                if (!updatableRouteCodes.contains(routeCode)) {
                    continue;
                }

                // --- 从JSON解析数据并构建对象 (此部分逻辑与您原来的一致) ---
                String value = entry.getValue();
                JSONArray jsonArray = JSONArray.parseArray(value);
                for (Object o : jsonArray) {
                    RoutePointDetail detail = new RoutePointDetail();
                    JSONObject jsonObject = JSONObject.parseObject(String.valueOf(o));
                    detail.setRouteCode(jsonObject.getString("MapID"));
                    detail.setCoordinates("x:" + jsonObject.get("PosX").toString() + ", y:" + jsonObject.get("PosY").toString());
                    detail.setPosX(jsonObject.getString("PosX"));
                    detail.setPosY(jsonObject.getString("PosY"));
                    detail.setAngleYaw(jsonObject.getString("AngleYaw"));
                    detail.setMapId(jsonObject.getString("MapID"));
                    detail.setPointCode(jsonObject.getString("Value"));
                    detail.setPointInfo(jsonObject.getString("PointInfo"));
                    detail.setSpeed(jsonObject.getString("Speed"));
                    detail.setNavMode(jsonObject.getString("NavMode"));
                    detail.setGait(jsonObject.getString("Gait"));
                    detail.setManner(jsonObject.getString("Manner"));
                    detail.setObsMode(jsonObject.getString("ObsMode"));
                    detail.setPosture(jsonObject.getString("Posture"));
                    detail.setTerrain(jsonObject.getString("Terrain"));
                    detail.setRouteCode(routeCode);
                    newDetailsToInsert.add(detail);
                }
            }

            // 4. 批量保存新的点位数据
            if (!newDetailsToInsert.isEmpty()) {
                saveBatch(newDetailsToInsert);
            }

        } catch (Exception e) {
            log.error(ExceptionUtil.getExceptionMessage(e));
            return -1;
        }

        return 0;
    }

    @Override
    @Async
    public synchronized Future<Integer> issueNavigation(String fileAbsPath) {
        try {
            taskStartTime = System.currentTimeMillis();
            pointCode = null;
            routeCode = fileAbsPath;
            LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
            queryWrapper.eq(RoutePointDetail::getRouteCode, fileAbsPath);
            queryWrapper.orderByAsc(RoutePointDetail::getPointCode);
            List<RoutePointDetail> details = baseMapper.selectList(queryWrapper);

            List<RoutePointDetail> collect = details.stream().filter(d -> "1".equals(d.getPointInfo())).collect(Collectors.toList());
            InspectionRecord inspectionRecord = new InspectionRecord();
            if (CollectionUtils.isNotEmpty(collect)) {
                RoutePointDetail detail = collect.get(0);
                inspectionRecord.setRouteCode(routeCode);
                inspectionRecord.setRouteName(detail.getRouteName());
                executingTask = detail.getRouteName();
                inspectionRecord.setTaskName(details.get(0).getRouteName());
                inspectionRecord.setTaskType("2");
                inspectionRecord.setStartTime(DateUtils.getNowDate());
                long count = details.stream().filter(o -> "1".equals(o.getPointInfo())).count();
                inspectionRecord.setLocationCount((int) count);
                inspectionRecord.setRegion(detail.getRegion());
                recordService.insertInspectionRecord(inspectionRecord);
            }

            Long recordId = inspectionRecord.getId();

            List<NavigationParameters> waypointList = new ArrayList<>();
            for (RoutePointDetail detail : details) {
                NavigationParameters navParams = getNavigationParameters(detail);
                navParams.setRecordId(recordId);
                waypointList.add(navParams);
            }

            // 使用默认的robotId和taskId，可以根据实际需求从其他地方获取
            Long robotId = 1L; // 默认机器人ID
            Long taskId = System.currentTimeMillis(); // 使用时间戳作为任务ID
            int result = sendCommand(waypointList, true, true, robotId, taskId);
            return new AsyncResult<>(result); // <--- 返回异步结果
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public synchronized int returnVoyage() {
        try {
            // 先取消导航
            isBreak = true;
            boolean isCancel = navigationControl.cancelNavigation();
            if (!isCancel) {
                return -2;
            }

            // 【修正 3】: 将 > 0 改为 >= 0，允许在第一个点位（索引0）失败时也能返航
            if (StringUtils.isNotEmpty(pointCode) && Integer.parseInt(pointCode) >= 0) {
                LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
                queryWrapper.eq(RoutePointDetail::getRouteCode, routeCode);
                queryWrapper.le(RoutePointDetail::getPointCode, pointCode);
                queryWrapper.orderByDesc(RoutePointDetail::getPointCode);
                List<RoutePointDetail> details = baseMapper.selectList(queryWrapper);
                List<NavigationParameters> waypointList = new ArrayList<>();
                for (RoutePointDetail detail : details) {
                    NavigationParameters navParams = getNavigationParameters(detail);
                    waypointList.add(navParams);
                }
                isBreak = false;
                // 使用默认的robotId和taskId，可以根据实际需求从其他地方获取
                Long robotId = 1L; // 默认机器人ID
                Long taskId = System.currentTimeMillis(); // 使用时间戳作为任务ID
                int i = sendCommand(waypointList, false, false, robotId, taskId);
                // 返航成功，执行充电
                if (i == 0) {
                    LambdaQueryWrapper<RoutePointDetail> wrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
                    // 【修正 1】: 将查询条件应用到正确的 wrapper 对象上
                    wrapper.like(RoutePointDetail::getRouteCode, "CHONGDIANRENWU");
                    wrapper.orderByAsc(RoutePointDetail::getPointCode);
                    List<RoutePointDetail> routes = baseMapper.selectList(wrapper);
                    List<NavigationParameters> pointList = new ArrayList<>();
                    for (RoutePointDetail detail : routes) {
                        NavigationParameters navParams = getNavigationParameters(detail);
                        pointList.add(navParams);
                    }
                    // 充电任务使用新的任务ID
                    Long chargingTaskId = System.currentTimeMillis();
                    i = sendCommand(pointList, false, true, robotId, chargingTaskId);
                }
                return i;
            }
            return -1;
        } catch (NumberFormatException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public synchronized int fixedPointNavigation(RoutePointDetail routePointDetail) {
        try {
            // 从RoutePointDetail中提取必要的参数
            String routeCode = routePointDetail.getRouteCode();
            String startValue = routePointDetail.getStartValue();
            String endValue = routePointDetail.getEndValue();

            // 验证参数
            if (StringUtils.isEmpty(routeCode) || StringUtils.isEmpty(startValue) || StringUtils.isEmpty(endValue)) {
                log.error("fixedPointNavigation参数不完整: routeCode={}, startValue={}, endValue={}",
                        routeCode, startValue, endValue);
                return -1;
            }

            this.routeCode = routeCode;

            // 解析起始和结束点位编号
            int startPoint = Integer.parseInt(startValue);
            int endPoint = Integer.parseInt(endValue);

            // 查询指定范围内的路线点位
            LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
            queryWrapper.eq(RoutePointDetail::getRouteCode, routeCode);
            if (endPoint > startPoint) {
                queryWrapper.between(RoutePointDetail::getPointCode, startPoint, endPoint);
                queryWrapper.orderByAsc(RoutePointDetail::getPointCode);
            } else {
                queryWrapper.between(RoutePointDetail::getPointCode, endPoint, startPoint);
                queryWrapper.orderByDesc(RoutePointDetail::getPointCode);
            }

            List<RoutePointDetail> details = baseMapper.selectList(queryWrapper);

            if (details.isEmpty()) {
                log.error("未找到路线编码为 {} 且点位编号在 {} 到 {} 范围内的路线点位",
                        routeCode, startPoint, endPoint);
                return -1;
            }
            RoutePointDetail detail = details.get(0);
            executingTask = detail.getRouteName();
            double startX = Double.parseDouble(detail.getPosX());
            double startY = Double.parseDouble(detail.getPosY());
            double distance = Math.sqrt(Math.pow(robotX - startX, 2) + Math.pow(robotY - startY, 2));
            if (distance > DISTANCE_THRESHOLD) {
                log.error("机器人距离导航起点太远，距离 = {}米 > 阈值: {}米，任务取消。",
                        distance, DISTANCE_THRESHOLD);
                return -2; // 返回错误码表示距离太远
            }

            LambdaQueryWrapper<InspectionRecord> recordWrapper = Wrappers.lambdaQuery(InspectionRecord.class);
            recordWrapper.eq(InspectionRecord::getRouteCode, routeCode);
            recordWrapper.orderByDesc(InspectionRecord::getStartTime);
            recordWrapper.isNotNull(InspectionRecord::getStopPoint).last("LIMIT 1");;
            InspectionRecord inspectionRecord = recordMapper.selectOne(recordWrapper);

            Long recordId = null;
            boolean isCheck = false;
            if (inspectionRecord != null) {
                recordId = inspectionRecord.getId();
                executingTask = detail.getRouteName();
                isCheck = true;
            }

            // 构建导航参数列表
            List<NavigationParameters> waypointList = new ArrayList<>();
            for (RoutePointDetail d : details) {
                NavigationParameters navParams = getNavigationParameters(d);
                if (recordId != null) {
                    navParams.setRecordId(recordId);
                }
                waypointList.add(navParams);
            }

            // 使用默认的robotId和taskId，可以根据实际需求从其他地方获取
            Long robotId = 1L; // 默认机器人ID
            Long taskId = System.currentTimeMillis(); // 使用时间戳作为任务ID

            log.info("开始执行定点导航: 路线={}, 起始点={}, 结束点={}, 共{}个点位",
                    routeCode, startPoint, endPoint, waypointList.size());

            return sendCommand(waypointList, isCheck, false, robotId, taskId);

        } catch (NumberFormatException e) {
            log.error("解析点位编号时发生错误: startValue={}, endValue={}",
                    routePointDetail.getStartValue(), routePointDetail.getEndValue(), e);
            return -1;
        } catch (Exception e) {
            log.error("执行定点导航时发生异常", e);
            return -1;
        }
    }

    // 视频类处理
    public void sendMessageToKafka(NavigationParameters currentPoint) {
        MultipartFile multipartFile = rtspFrameCaptureWithJavaCV.captureFrameAsMultipartFile();
        String fileUrl = minioService.uploadFile(multipartFile);

        // 保存当前点位巡检详情
        InspectionRecordDetails details = new InspectionRecordDetails();
        details.setTaskName(currentPoint.getTaskName());
        details.setSensorType("3");
        details.setPointCode(currentPoint.getPointCode());
        details.setPointName(currentPoint.getPointName());
        details.setSensorId(2L);
        details.setUrl(fileUrl);
        details.setRecordId(currentPoint.getRecordId());
        details.setCreateTime(new Date());
        recordDetailsMapper.insert(details);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("type", "1");
        jsonObject.put("workShop", "装配车间");
        jsonObject.put("deviceName", "四足机器人");
        jsonObject.put("pointName", currentPoint.getPointName());
        jsonObject.put("behaviorName", "杂物");
        jsonObject.put("captureTime", System.currentTimeMillis());
        jsonObject.put("backgroundPicUrl", fileUrl);
        String model = StringUtils.isNotEmpty(currentPoint.getModel()) ? currentPoint.getModel() : "4";
        String checkModel = sysDictDataService.selectDictLabel("check_model", model);
        jsonObject.put("model", checkModel);
        jsonObject.put("pointCode", currentPoint.getPointCode());
        kafkaProducerService.sendMessage(jsonObject.toJSONString());
        log.info("发送kafka消息=======================================================================");
    }


    // 温度、气体类型处理
    private void temperatureProcess(NavigationParameters currentPoint) {
        log.info("温度检测=======================================================================");
        // 温度检测
        String temperatureCheck = currentPoint.getTemperatureCheck();
        currentPoint.setDeviceType("1");
        if (StringUtils.isNotEmpty(temperatureCheck)) {
            Float latestTemperature = modbusTcpHeatServer.getLatestTemperature();
            boolean t = dynamicRuleValidator.validate(temperatureCheck, "t", latestTemperature);
            if (!t) { // 报警
                saveAlarmRecordDetails(currentPoint, "温度传感器报警，传感器温度为：" + latestTemperature + " ℃");
            } else {
                saveNormalRecordDetails(currentPoint, String.valueOf(latestTemperature));
            }
        }
    }

    private void gasProcess(NavigationParameters currentPoint) {
        log.info("气体检测=======================================================================");
        // 气体检测
        String latestGas = modbusTcpGasServer.getLatestGas();
        currentPoint.setDeviceType("2");
        if (StringUtils.isNotEmpty(latestGas) && !latestGas.contains("正常")) { // 报警
            saveAlarmRecordDetails(currentPoint, latestGas);
        } else {
            saveNormalRecordDetails(currentPoint, latestGas);
        }
    }

    private void saveAlarmRecordDetails(NavigationParameters currentPoint, String alarmInfo) {
        InspectionRecordDetails details = new InspectionRecordDetails();
        details.setTaskName(currentPoint.getTaskName());
        details.setSensorType(currentPoint.getDeviceType());
        details.setPointCode(currentPoint.getPointCode());
        details.setPointName(currentPoint.getPointName());
        details.setRecordId(currentPoint.getRecordId());
        details.setCreateTime(new Date());
        details.setAlarmTime(new Date());
        details.setAlarmInfo(alarmInfo);
        details.setAlarmType("1");
        recordDetailsMapper.insert(details);
    }

    private void saveNormalRecordDetails(NavigationParameters currentPoint, String latestGas) {
        InspectionRecordDetails details = new InspectionRecordDetails();
        details.setTaskName(currentPoint.getTaskName());
        details.setSensorType(currentPoint.getDeviceType());
        details.setPointCode(currentPoint.getPointCode());
        details.setPointName(currentPoint.getPointName());
        details.setRecordId(currentPoint.getRecordId());
        details.setPointValue(latestGas);
        details.setCreateTime(new Date());
        recordDetailsMapper.insert(details);
    }

    private int sendCommand(List<NavigationParameters> waypointList, boolean isCheck, boolean isAsc, Long robotId, Long taskId) {
        startPlayer = true;
        int result = 0;
        AtomicInteger num = new AtomicInteger();
        ExecutorService executor = Executors.newSingleThreadExecutor();

        log.info("准备在后台线程中开始执行导航序列...");

        // 启动机器人坐标监控
        if (robotId != null && taskId != null) {
            try {
                //robotCoordinateMonitorService.startMonitoring(robotId, taskId);
                log.info("已启动机器人坐标监控: robotId={}, taskId={}", robotId, taskId);
            } catch (Exception e) {
                log.error("启动机器人坐标监控失败: robotId={}, taskId={}, error={}", robotId, taskId, e.getMessage(), e);
            }
        }

        List<NavigationParameters> sortedWaypointList;
        if (isAsc) {
            sortedWaypointList = waypointList.stream()
                    .sorted(Comparator.comparingInt(NavigationParameters::getValue))
                    .collect(Collectors.toList());
        } else {
            sortedWaypointList = waypointList;
        }
        // 提交一个返回布尔值的任务，true代表序列全部成功，false代表中途失败
        Future<Boolean> sequenceResult;
        try {
            sequenceResult = executor.submit(() -> {
                for (int i = 0; i < sortedWaypointList.size(); i++) {
                    if (isCancelNavigation) {
                        isCancelNavigation = false;
                        break;
                    }

                    pointCode = String.valueOf(i);
                    NavigationParameters currentPoint = sortedWaypointList.get(i);

                    if (isBreak) {
                        return false;
                    }

                    Future<?> kafkaMonitorFuture = null;

                    // 【关键修正】: 在导航开始前，为本次任务点启动一个并行的监视器线程
                    if (isCheck) {
                        kafkaMonitorFuture = executorService.submit(() -> {
                            log.debug("点位 [{}] 的Kafka监视器已启动...", currentPoint.getPointName());

                            // 监视器循环，直到被主线程中断
                            while (!Thread.currentThread().isInterrupted()) {
                                try {
                                    String deviceType = currentPoint.getDeviceType();
                                    if (StringUtils.isNotEmpty(deviceType)) {
                                        List<String> deviceTypes = Arrays.asList(deviceType.split(";"));
                                        // 条件：步态存在且不为4（踏步）
                                        if (UnifiedUDPReceiver.lastRobotGaitState != null && UnifiedUDPReceiver.lastRobotGaitState != 4
                                                && StringUtils.isNotEmpty(currentPoint.getPointName())) {
                                            log.info("点位 [{}] 检测到非标准步态 (状态={})，触发图像抓取。",
                                                    currentPoint.getPointName(), UnifiedUDPReceiver.lastRobotGaitState);

                                            // 调用抓图和发送逻辑
                                            // 温度检测
                                            if (deviceTypes.contains("1")) {
                                                temperatureProcess(currentPoint);
                                            }
                                            // 气体检测
                                            if (deviceTypes.contains("2")) {
                                                gasProcess(currentPoint);
                                            }
                                            // 视频检测
                                            if (deviceTypes.contains("3")) {
                                                // 安排任务在1秒后，在公共的 ForkJoinPool 中执行
                                                CompletableFuture.runAsync(() -> {

                                                    log.info("延迟1秒后执行：发送Kafka消息...");
                                                    sendMessageToKafka(currentPoint);

                                                }, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS));
                                            }
                                        }

                                        // 打开自动门
                                        if (deviceTypes.contains("4")) {
                                            modbusTcpIoServer.sendRelayCommand("1");
                                            modbusTcpIoServer.sendRelayCommand("2");
                                        }

                                        // 关闭自动门
                                        if (deviceTypes.contains("5")) {
                                            modbusTcpIoServer.sendRelayCommand("3");
                                            modbusTcpIoServer.sendRelayCommand("4");
                                        }

                                        // 【重要】: 成功触发一次后，立即退出循环，防止消息风暴
                                        break;
                                    }

                                    // 每隔500毫秒检查一次，避免CPU空转
                                    Thread.sleep(500);

                                } catch (InterruptedException e) {
                                    // 这是主线程发出的停止信号，正常退出
                                    log.debug("点位 [{}] 的Kafka监视器被中断，正常停止。", currentPoint.getPointName());
                                    // 恢复中断状态并退出循环
                                    Thread.currentThread().interrupt();
                                    break;
                                } catch (Exception e) {
                                    log.error("点位 [{}] 的Kafka监视器线程出现异常，将停止: {}",
                                            currentPoint.getPointName(), e.getMessage());
                                    break; // 出现未知异常时也应停止
                                }
                            }
                            log.debug("点位 [{}] 的Kafka监视器线程已结束。", currentPoint.getPointName());
                        });
                    }

                    System.out.printf("\n---> 正在执行导航序列: 第 %d/%d 个任务点 (Value: %d)\n", i + 1, sortedWaypointList.size(), currentPoint.getValue());

                    // 执行【阻塞】的导航命令，此时上面的监视器线程正在后台并行运行
                    int resultCode = navigator.sendNavigationCommandAndWait(currentPoint);

                    // 【关键修正】: 导航结束后，无论成功或失败，都立即停止该任务点的监视器线程
                    if (kafkaMonitorFuture != null && !kafkaMonitorFuture.isDone()) {
                        kafkaMonitorFuture.cancel(true); // 'true'会中断正在执行的线程
                    }

                    if (resultCode == 0) {
                        num.getAndIncrement();
                        log.info("---> 任务点 %d [成功] = {}", currentPoint.getValue());
                    } else {
                        log.error("---> 任务点 = {} [失败]. ErrorCode: = {}. 中止导航序列。",
                                currentPoint.getValue(), resultCode);
                        return false; // 返回 false，表示序列执行失败
                    }
                }
                return true; // 所有点都成功，返回 true
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // =================================================================
        // 3. 等待整个序列执行完毕并获取最终结果
        // =================================================================

        try {
            boolean wasSuccessful = sequenceResult.get(); // 阻塞，直到整个序列完成或中止
            if (wasSuccessful) {
                log.info("[最终结果]: 导航序列中的所有任务点均已成功执行完毕。");
            } else {
                log.info("[最终结果]: 导航序列因某个任务点失败而中止。");
                result = -1;
            }
        } catch (Exception e) {
            log.error("执行导航序列时发生异常: {}", e.getMessage());
            result = -1;
            e.printStackTrace();
        } finally {
            executor.shutdown();

            // 停止机器人坐标监控
            if (robotId != null && taskId != null) {
                try {
                    robotCoordinateMonitorService.stopMonitoring(robotId, taskId);
                    log.info("已停止机器人坐标监控: robotId={}, taskId={}", robotId, taskId);
                } catch (Exception e) {
                    log.error("停止机器人坐标监控失败: robotId={}, taskId={}, error={}", robotId, taskId, e.getMessage(), e);
                }
            }
            startPlayer = false;
            executingTask = null;
        }

        if (isCheck) {
            int size = waypointList.size();
            Long recordId = waypointList.get(0).getRecordId();
            InspectionRecord inspectionRecord = new InspectionRecord();
            inspectionRecord.setId(recordId);
            inspectionRecord.setEndTime(new Date());
            inspectionRecord.setMissedCheckCount(size - num.get());

            LambdaUpdateWrapper<InspectionRecordDetails> wrapper = Wrappers.lambdaUpdate(InspectionRecordDetails.class);
            wrapper.eq(InspectionRecordDetails::getRecordId, recordId);
            List<InspectionRecordDetails> details = recordDetailsMapper.selectList(wrapper);
            if (CollectionUtils.isNotEmpty(details)) {
                long alarmCount = details.stream().filter(d -> StringUtils.isNotEmpty(d.getAlarmInfo())).count();
                long count = details.stream().filter(d -> StringUtils.isEmpty(d.getAlarmInfo())).count();
                inspectionRecord.setNormalCheckCount((int) count);
                inspectionRecord.setAlarmCheckCount((int) alarmCount);
            }
            if (result == -1) {
                inspectionRecord.setStatus("1");
                inspectionRecord.setStopPoint(pointCode);
            } else {
                inspectionRecord.setStatus("2");
            }
            long l = System.currentTimeMillis() - taskStartTime;
            long minutes = TimeUnit.MILLISECONDS.toMinutes(l);
            inspectionRecord.setUseTime((int) minutes);
            recordService.updateById(inspectionRecord);
        }
        return result;
    }

    /**
     * 检查指定导航点位区域的传感器数据是否符合标准
     *
     * @param navigationParams 导航参数，包含点位信息
     * @return true-符合标准可以继续导航，false-不符合标准需要停止导航
     */
    private boolean checkSensorDataStandards(NavigationParameters navigationParams) {
        try {
            // 获取机器人当前坐标
            Double currentX = getCurrentRobotX();
            Double currentY = getCurrentRobotY();
            Double currentZ = getCurrentRobotZ();

            if (currentX == null || currentY == null) {
                log.warn("无法获取机器人当前坐标，使用导航参数推断区域");
                // 如果无法获取坐标，回退到原有逻辑
                String regionCode = getRegionCodeFromNavigationParams(navigationParams);
                if (StringUtils.isEmpty(regionCode)) {
                    log.warn("导航点位 {} 未配置区域信息，跳过传感器数据检查", navigationParams.getValue());
                    return true;
                }
                return checkSensorDataByRegion(regionCode);
            }

            // 根据坐标判断机器人所在区域
            String regionCode = coordinateRegionService.getRegionByCoordinate(currentX, currentY, currentZ != null ? currentZ : 0.0);
            if (StringUtils.isEmpty(regionCode)) {
                log.warn("机器人当前坐标 ({}, {}, {}) 未匹配到任何区域，跳过传感器数据检查", currentX, currentY, currentZ);
                return true; // 没有区域信息时默认允许通过
            }

            log.info("机器人当前坐标: ({}, {}, {})，所在区域: {}", currentX, currentY, currentZ, regionCode);
            return checkSensorDataByRegion(regionCode);

        } catch (Exception e) {
            log.error("检查传感器数据标准时发生异常: {}", e.getMessage(), e);
            return true; // 异常情况下默认允许继续，避免因检查逻辑问题影响正常导航
        }
    }

    /**
     * 获取机器人当前X坐标
     */
    private Double getCurrentRobotX() {
        try {
            if (RobotMonitor.xyList != null && !RobotMonitor.xyList.isEmpty()) {
                Object lastEntry = RobotMonitor.xyList.get(RobotMonitor.xyList.size() - 1);
                if (lastEntry instanceof JSONObject) {
                    JSONObject jsonObject = (JSONObject) lastEntry;
                    return jsonObject.getDouble("x");
                }
            }
        } catch (Exception e) {
            log.warn("获取机器人X坐标失败: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 获取机器人当前Y坐标
     */
    private Double getCurrentRobotY() {
        try {
            if (RobotMonitor.xyList != null && !RobotMonitor.xyList.isEmpty()) {
                Object lastEntry = RobotMonitor.xyList.get(RobotMonitor.xyList.size() - 1);
                if (lastEntry instanceof JSONObject) {
                    JSONObject jsonObject = (JSONObject) lastEntry;
                    return jsonObject.getDouble("y");
                }
            }
        } catch (Exception e) {
            log.warn("获取机器人Y坐标失败: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 获取机器人当前Z坐标
     */
    private Double getCurrentRobotZ() {
        try {
            if (RobotMonitor.xyList != null && !RobotMonitor.xyList.isEmpty()) {
                Object lastEntry = RobotMonitor.xyList.get(RobotMonitor.xyList.size() - 1);
                if (lastEntry instanceof JSONObject) {
                    JSONObject jsonObject = (JSONObject) lastEntry;
                    return jsonObject.getDouble("z");
                }
            }
        } catch (Exception e) {
            log.warn("获取机器人Z坐标失败: {}", e.getMessage());
        }
        return null;
    }

    /**
     * 根据区域代码检查传感器数据标准
     */
    private boolean checkSensorDataByRegion(String regionCode) {
        try {
            log.info("开始检查区域 {} 的传感器数据标准符合性", regionCode);

            // 获取该区域的所有传感器类型标准配置
            List<RegionStandard> regionStandards = regionStandardService.selectRegionStandardByCode(regionCode);
            if (regionStandards == null || regionStandards.isEmpty()) {
                log.warn("区域 {} 未配置传感器标准，跳过检查", regionCode);
                return true; // 没有标准配置时默认允许通过
            }

            boolean allStandardsMet = true;
            StringBuilder violationDetails = new StringBuilder();

            // 检查每种传感器类型的最新数据
            for (RegionStandard standard : regionStandards) {
                String sensorType = standard.getSensorType();

                // 获取该区域该传感器类型的最新数据
                List<SensorData> latestData = sensorDataService.selectLatestSensorData(regionCode, sensorType, 1);

                if (latestData == null || latestData.isEmpty()) {
                    log.warn("区域 {} 传感器类型 {} 无最新数据，跳过检查", regionCode, sensorType);
                    continue;
                }

                SensorData sensorData = latestData.get(0);

                // 使用判断服务检查数据是否符合标准
                boolean isStandard = sensorDataJudgementService.judge(sensorData, standard);

                if (!isStandard) {
                    allStandardsMet = false;
                    String violation = String.format("传感器类型: %s, 当前值: %s, 状态: %s",
                            sensorType, sensorData.getValue(), sensorData.getDetectStatus());
                    violationDetails.append(violation).append("; ");

                    // 如果是危险级别，立即停止
                    if ("danger".equals(sensorData.getDetectStatus())) {
                        log.error("区域 {} 检测到危险级别传感器数据: {}", regionCode, violation);
                        return false;
                    }
                }
            }

            if (!allStandardsMet) {
                log.warn("区域 {} 传感器数据不完全符合标准: {}", regionCode, violationDetails);

                // 检查是否有未处理的异常数据
                List<SensorData> unhandledAbnormal = sensorDataService.selectUnhandledAbnormalSensorData();
                long regionAbnormalCount = unhandledAbnormal.stream()
                        .filter(data -> regionCode.equals(data.getRegionCode()))
                        .count();

                if (regionAbnormalCount > 0) {
                    log.error("区域 {} 存在 {} 条未处理的异常传感器数据，停止导航", regionCode, regionAbnormalCount);
                    return false;
                }
            }

            log.info("区域 {} 传感器数据检查完成，结果: {}", regionCode, allStandardsMet ? "符合标准" : "部分不符合但可继续");
            return true; // 即使部分不符合，如果不是危险级别且无未处理异常，仍可继续

        } catch (Exception e) {
            log.error("检查区域 {} 传感器数据标准时发生异常: {}", regionCode, e.getMessage(), e);
            return true; // 异常情况下默认允许继续，避免因检查逻辑问题影响正常导航
        }
    }

    /**
     * 从导航参数中获取区域代码
     *
     * @param navigationParams 导航参数
     * @return 区域代码
     */
    private String getRegionCodeFromNavigationParams(NavigationParameters navigationParams) {
        try {
            // 根据导航参数的点位信息查询对应的路线点位详情
            LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
            queryWrapper.eq(RoutePointDetail::getRouteCode, routeCode);
            queryWrapper.eq(RoutePointDetail::getPointCode, String.valueOf(navigationParams.getValue()));

            RoutePointDetail pointDetail = baseMapper.selectOne(queryWrapper);
            if (pointDetail != null && StringUtils.isNotEmpty(pointDetail.getRegion())) {
                return pointDetail.getRegion();
            }

            // 如果没有找到具体点位的区域信息，可以根据点位名称或其他逻辑推断
            String pointName = navigationParams.getPointName();
            if (StringUtils.isNotEmpty(pointName)) {
                // 这里可以根据点位名称的命名规则来推断区域
                // 例如：如果点位名称包含"电箱"，可能属于"电气区域"
                if (pointName.contains("电箱")) {
                    return "ELECTRICAL_AREA";
                } else if (pointName.contains("消防栓")) {
                    return "FIRE_SAFETY_AREA";
                }
            }

            return null;
        } catch (Exception e) {
            log.error("获取导航点位区域代码时发生异常: {}", e.getMessage(), e);
            return null;
        }
    }

    @NotNull
    private NavigationParameters getNavigationParameters(RoutePointDetail detail) {
        NavigationParameters navParams = new NavigationParameters();
        navParams.setPointName(detail.getPointName());
        navParams.setCheckType(detail.getCheckType());
        navParams.setTaskName(detail.getRouteName());
        navParams.setPointCode(detail.getPointCode());
        navParams.setDeviceType(detail.getDeviceType());
        navParams.setTemperatureCheck(detail.getTemperatureCheck());
        navParams.setGasCheck(detail.getGasCheck());
        navParams.setModel(detail.getModel());

        navParams.setPosX(Float.parseFloat(detail.getPosX()));
        navParams.setPosY(Float.parseFloat(detail.getPosY()));
        navParams.setPointInfo(Integer.parseInt(detail.getPointInfo()));
        navParams.setAngleYaw(Float.parseFloat(detail.getAngleYaw())); // 大约 28 度
        navParams.setGait(Integer.parseInt(detail.getGait())); // 行走步态
        navParams.setSpeed(Integer.parseInt(detail.getSpeed())); // 低速
        navParams.setNavMode(Integer.parseInt(detail.getNavMode())); // 自主导航
        navParams.setMapID(Integer.parseInt(detail.getMapId()));
        navParams.setValue(Integer.parseInt(detail.getPointCode()));

        navParams.setManner(Integer.parseInt(detail.getManner()));
        navParams.setObsMode(Integer.parseInt(detail.getObsMode()));
        navParams.setPosture(Integer.parseInt(detail.getPosture()));
        navParams.setTerrain(Integer.parseInt(detail.getTerrain()));
        return navParams;
    }

    @Override
    public RoutePointDetail selectRoutePointDetailByRouteCodeAndPointCode(String routeCode, String pointCode) {
        LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
        queryWrapper.eq(StringUtils.isNotEmpty(routeCode), RoutePointDetail::getRouteCode, routeCode);
        queryWrapper.eq(StringUtils.isNotEmpty(pointCode), RoutePointDetail::getPointCode, pointCode);
        queryWrapper.last("LIMIT 1");
        return routePointDetailMapper.selectOne(queryWrapper);
    }

    @Override
    public List<RoutePointDetail> getRoute() {
        QueryWrapper<RoutePointDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("DISTINCT route_code, route_name");
        return routePointDetailMapper.selectList(queryWrapper);
    }

    @Override
    public List<RoutePointDetail> getList(RoutePointDetail routePointDetail) {
        LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
        queryWrapper.eq(StringUtils.isNotEmpty(routePointDetail.getRouteCode()), RoutePointDetail::getRouteCode, routePointDetail.getRouteCode());
        queryWrapper.like(StringUtils.isNotEmpty(routePointDetail.getRouteName()), RoutePointDetail::getRouteName, routePointDetail.getRouteName());
        queryWrapper.like(StringUtils.isNotEmpty(routePointDetail.getPointName()), RoutePointDetail::getPointName, routePointDetail.getPointName());
        queryWrapper.like(StringUtils.isNotEmpty(routePointDetail.getRegion()), RoutePointDetail::getRegion, routePointDetail.getRegion());
        return routePointDetailMapper.selectList(queryWrapper);
    }

    @Override
    public List<Map<String, Object>> aboutToExecuteList() {
        SysJob sysJob = new SysJob();
        sysJob.setStatus("0");
        List<SysJob> sysJobs = sysJobMapper.selectJobList(sysJob);
        List<Map<String, Object>> jobs = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        for (SysJob job : sysJobs) {
            List<LocalDateTime> times = getTodayExecutions(job.getCronExpression());
            String jobName = job.getJobName();
            for (LocalDateTime time : times) {
                if (time.isAfter(now)) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("jobName", jobName);
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
                    // 3. 格式化 LocalDateTime
                    String formattedTime = time.format(formatter);
                    map.put("time", formattedTime);
                    jobs.add(map);
                }
            }
        }
        return jobs;
    }

    @Override
    public int taskNavigation(RoutePointDetail routePointDetail) {
        LambdaQueryWrapper<RoutePointDetail> queryWrapper = Wrappers.lambdaQuery(RoutePointDetail.class);
        queryWrapper.eq(RoutePointDetail::getRouteCode, routePointDetail.getRouteCode());
        List<RoutePointDetail> details = baseMapper.selectList(queryWrapper);
        double distance = Double.MAX_VALUE;
        String startValue = null;
        for (RoutePointDetail detail : details) {
            double startX = Double.parseDouble(detail.getPosX());
            double startY = Double.parseDouble(detail.getPosY());
            double d = Math.sqrt(Math.pow(robotX - startX, 2) + Math.pow(robotY - startY, 2));
            if (d < distance) {
                distance = d;
                startValue = detail.getPointCode();
            }
        }
        if (distance > DISTANCE_THRESHOLD) {
            log.error("机器人距离导航起点太远，距离 = {}米 > 阈值: {}米，任务取消。",
                    distance, DISTANCE_THRESHOLD);
            return -2; // 返回错误码表示距离太远
        }
        routePointDetail.setStartValue(startValue);
        routePointDetail.setEndValue(routePointDetail.getPointCode());
        return fixedPointNavigation(routePointDetail);
    }


    public static List<LocalDateTime> getTodayExecutions(String cron) {
        try {
            List<LocalDateTime> times = new ArrayList<>();
            CronExpression cronExpression = new CronExpression(cron);

            // 当天开始时间
            LocalDate today = LocalDate.now();
            ZonedDateTime startOfDay = today.atStartOfDay(ZoneId.systemDefault());
            ZonedDateTime endOfDay = today.plusDays(1).atStartOfDay(ZoneId.systemDefault());

            Date next = Date.from(startOfDay.toInstant());

            while (true) {
                next = cronExpression.getNextValidTimeAfter(next);
                if (next == null || next.toInstant().isAfter(endOfDay.toInstant())) {
                    break;
                }
                times.add(LocalDateTime.ofInstant(next.toInstant(), ZoneId.systemDefault()));
            }

            return times;
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

}
